/**
 * @(#)HibernateSpringEntityDAO.java
 *
 * Copyright (c) 2010 sinba, Inc. All Rights Reserved.
 */
package com.sinba.common.dao;

import com.sinba.common.dto.PageDTO;
import com.sinba.common.entity.BaseDomainEntity;
import com.sinba.common.exception.ApplicationException;
import com.sinba.common.util.Assert;

import org.apache.commons.beanutils.PropertyUtils;

import org.apache.log4j.Logger;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Session;

import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import org.hibernate.impl.CriteriaImpl;
import org.hibernate.impl.CriteriaImpl.OrderEntry;

import org.hibernate.metadata.ClassMetadata;

import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import org.springframework.util.ReflectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


/**
 * Implementation of the IEntityDAO interface using the Spring Hibernate
 * template API. HibernateDaoSupport is a convenient super class for
 * Hibernate-based data access objects.
 * @version 1.00 2010-7-16
 * @author <a href="mailto:sinbawang@msn.com">Sinba Wang</a>
 * @param <T> the generic type of domain entity
 */
public abstract class BaseDAOImplHibernate<T>
    extends HibernateDaoSupport
    implements IEntityDAO<T>
{
    /** LOGGER object. */
    private static final Logger LOGGER = Logger.getLogger( BaseDAOImplHibernate.class );

    /** the class of domain entity. */
    private Class<T> entityClass;

    /**
     * Default Constructor.
     */
    @SuppressWarnings( "unchecked" )
    public BaseDAOImplHibernate(  )
    {
//    	Type t = getClass(  ).getGenericSuperclass();
//    	if (t instanceof ParameterizedType) {
//    		this.entityClass = (Class<T>) ( (ParameterizedType) t ).getActualTypeArguments(  )[0];
//    	}
        this.entityClass = (Class<T>) ( (ParameterizedType) getClass(  ).getGenericSuperclass(  ) ).getActualTypeArguments(  )[0];
    }

    /**
     * Find list of entities by given ids.
     * @param ids the given ids
     * @return the list of entities
     */
    public List<T> findByIds( Serializable[] ids )
    {
    	Assert.notNull(ids, "fail find entities:ids is null");
        String hql = "from " + entityClass.getName(  ) + " where " + this.getIdName(  ) + " in (:ids)";
        List<T> entities = getHibernateTemplate(  ).findByNamedParam( hql, "ids", ids );

        return entities;
    }

    /**
     * Delete the designated entities by given ids.
     * @param ids the given ids
     */
    public void deleteByIds( Serializable[] ids )
    {
    	Assert.notNull(ids, "fail delete entities:ids is null");
        List<T> entities = findByIds( ids );

        for ( T entity : entities )
        {
            this.delete( entity );
        }
    }

    /**
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#save(java.lang.Object)
     */
    public void save( T entity )
    {
        getHibernateTemplate(  ).save( entity );
    }

    /**
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#update(java.lang.Object)
     */
    public void update( T entity )
    {
        getHibernateTemplate(  ).saveOrUpdate( entity );
    }

    /**
     * @see com.sinba.common.dao.IEntityDAO#saveOrUpdateAll(java.util.Collection
     * )
     */
    public void updateAll( Collection<T> entities )
    {
        getHibernateTemplate(  ).saveOrUpdateAll( entities );
    }

    /**
     * @see com.sinba.common.dao.IEntityDAO#merge(java.lang.Object)
     */
    public T merge( T entity )
    {
//    	 //不能编辑系统数据 Van
//    	 if (entity instanceof BaseDomainEntity ){
//    		 
//               BaseDomainEntity domainEntity = (BaseDomainEntity) entity;
//               if(domainEntity.getDataFlag()!=null && domainEntity.getDataFlag()==1){
//            	   throw new ApplicationException("ERROR_SYSTEM_DATA_CAN_NOT_EDIT","系统数据，不能被修改~");
//               }
//         }
//    	
//    	
        return getHibernateTemplate().merge( entity );
    }

    /**
     * @see com.sinba.common.dao.IEntityDAO#mergeAll(java.util.Collection)
     */
    public Collection<Object> mergeAll( Collection<T> entities )
    {
        List<Object> updatedPersistentInstances = null;

        if ( ( entities != null ) && ( entities.size(  ) > 0 ) )
        {
            updatedPersistentInstances = new ArrayList<Object>(  );

            for ( Object entity : entities )
            {
                updatedPersistentInstances.add( getHibernateTemplate(  ).merge( entity ) );
            }
        }

        return updatedPersistentInstances;
    }

    /**
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#delete(java.lang.Object)
     */
    public void delete( T entity ){
    	
    	//Van
        if ( entity instanceof BaseDomainEntity){
        	
            BaseDomainEntity domainEntity = (BaseDomainEntity) entity;    
            Byte dataFlag=domainEntity.getDataFlag();
            if(dataFlag!=null && dataFlag.equals((byte)1)){
            	throw new ApplicationException("ERROR_SYSTEM_DATA_CAN_NOT_DELETE","系统数据不能被删除~");
            }
           
        } 
         getHibernateTemplate().delete( entity );
    }
    
    
	public void purge(T entity) {
		getHibernateTemplate().delete(entity);
	}
    /*
     * @see com.sinba.common.dao.IEntityDAO#deleteAll()
     */
    public void deleteAll(  )
    {
        getHibernateTemplate(  ).deleteAll( findByCriteria(  ) );
    }

    /*
     * @see com.sinba.common.dao.IEntityDAO#deleteAll(java.util.Collection)
     */
    public void deleteAll( Collection<T> entities )
    {
        getHibernateTemplate(  ).deleteAll( entities );
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findById(java.io.Serializable)
     */
    public T findById( Serializable id )
    {
    	Assert.notNull(id, "fail find entity:ids is null");
        return (T) getHibernateTemplate(  ).get( getEntityClass(  ),
                                                 id );
    }
    /**
     * 如果查询结果为空，则抛出异常ERROR_DATA_NO_LONGER_EXISTS
     * @author Guoyu_Tan
     * @param id
     * @return
     */
    public T findById( Serializable id,String nullException)
    {
    	Assert.notNull(id, "fail find entity:ids is null");
    	T t = getHibernateTemplate(  ).get( getEntityClass(  ),
                id );
    	if(t==null)
    		throw new ApplicationException("ERROR_DATA_NO_LONGER_EXISTS","数据已经不存在!");
        return t;
    }
    
    
    public T loadById( Serializable id )
    {
    	Assert.notNull(id, "fail find entity:ids is null");
        return (T) getHibernateTemplate(  ).load( getEntityClass(  ),
                                                 id );
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findById(java.io.Serializable,
     * boolean)
     */
    @SuppressWarnings( "unchecked" )
    public T findById( Serializable id, boolean lock )
    {
    	Assert.notNull(id, "fail find entity:ids is null");
        T entity;

        if ( lock )
        {
            entity =
                (T) getHibernateTemplate(  ).get( getEntityClass(  ),
                                                  id,
                                                  LockMode.UPGRADE );
        } else
        {
            entity =
                (T) getHibernateTemplate(  ).get( getEntityClass(  ),
                                                  id );
        }

        return entity;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findAll()
     */
    public List<T> findAll(  )
    {
        return findByCriteria(  );
    }

    @SuppressWarnings( "unchecked" )
    public List<T> findByExample( T exampleInstance )
    {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass( getEntityClass(  ) );
        Example example = Example.create( exampleInstance );

        detachedCriteria.add( example );

        return getHibernateTemplate(  ).findByCriteria( detachedCriteria );
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findByExample(java.lang.Object,
     * java.lang.String[])
     */
    @SuppressWarnings( "unchecked" )
    public List<T> findByExample( T exampleInstance, String... excludedProperties )
    {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass( getEntityClass(  ) );
        Example example = Example.create( exampleInstance );

        for ( String excludedProperty : excludedProperties )
        {
            example.excludeProperty( excludedProperty );
        }

        detachedCriteria.add( example );

        return getHibernateTemplate(  ).findByCriteria( detachedCriteria );
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findBy(java.lang.String,
     * java.lang.Object)
     */
    public List<T> findBy( String propertyName, Object value )
    {
        Assert.hasText( propertyName );

        return findByCriteria( Restrictions.eq( propertyName, value ) );
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findBy(java.lang.String,
     * java.lang.Object, java.lang.String, boolean)
     */
    public List<T> findBy( String propertyName, Object value, String orderBy, boolean isAsc )
    {
        Assert.hasText( propertyName );
        Assert.hasText( orderBy );

        return findByCriteria( orderBy,
                               isAsc,
                               Restrictions.eq( propertyName, value ) );
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#findUniqueBy(java.lang.String,
     * java.lang.Object)
     */
    @SuppressWarnings( "unchecked" )
    public T findUniqueBy( String propertyName, Object value )
    {
        Assert.hasText( propertyName );

        DetachedCriteria dc = createCriteria( Restrictions.eq( propertyName, value ) );
        List<T> entities = getHibernateTemplate(  ).findByCriteria( dc );

        if ( entities.size(  ) > 0 )
        {
            return entities.get( 0 );
        } else
        {
            return null;
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see com.sinba.common.dao.IEntityDAO#isUnique(java.lang.Object,
     * java.lang.String)
     */
    public boolean isUnique( T entity, String uniquePropertyNames )
    {
        Assert.hasText( uniquePropertyNames );

        DetachedCriteria criteria = createCriteria(  ).setProjection( Projections.rowCount(  ) );
        String[] namesList = uniquePropertyNames.split( "," );

        try
        {
            for ( String name : namesList )
            {
                criteria.add( Restrictions.eq( name,
                                               PropertyUtils.getProperty( entity, name ) ) );
            }

            // if id!=null, then object has already been exist, add judge for
            // except itself?
            String idName = getIdName(  );
            Serializable id = getId( entity );

            if ( id != null )
            {
                criteria.add( Restrictions.not( Restrictions.eq( idName, id ) ) );
            }
        } catch ( Exception e )
        {
            ReflectionUtils.handleReflectionException( e );
        }

        return (Integer) getHibernateTemplate(  ).findByCriteria( criteria ).get( 0 ) == 0;
    }

    /**
     * A convenience method to get the identifier of the persistent instance.
     *
     * @param entity
     *
     * @return
     */
    protected Serializable getId( T entity )
                          throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        Assert.notNull( entity );
        Assert.notNull( entityClass );

        return (Serializable) PropertyUtils.getProperty( entity,
                                                         getIdName(  ) );
    }

    /**
     * A convenience method to get the identifier name of the persistent
     * instance.
     *
     * @return
     */
    protected String getIdName(  )
    {
        Assert.notNull( getEntityClass(  ) );

        ClassMetadata meta = getSessionFactory(  ).getClassMetadata( getEntityClass(  ) );

        Assert.notNull( meta, "Class " + getEntityClass(  ) + " not define in hibernate session factory." );

        String idName = meta.getIdentifierPropertyName(  );

        Assert.hasText( idName, getEntityClass(  ).getSimpleName(  ) + " has no identifier property define." );

        return idName;
    }

    /**
     * Use this inside subclasses as a convenience method.
     *
     * @param criterion
     * @return
     */
    @SuppressWarnings( "unchecked" )
    protected List<T> findByCriteria( Criterion... criterions )
    {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass( getEntityClass(  ) );
        for ( Criterion criterion : criterions )
        {
            detachedCriteria.add( criterion );
        }

        if ( BaseDomainEntity.class.isAssignableFrom( entityClass ) )
        {
            detachedCriteria.add( Restrictions.ne( "dataFlag",
                                                   BaseDomainEntity.DELETED.byteValue(  ) ) );
        }

        return getHibernateTemplate(  ).findByCriteria( detachedCriteria );
    }

    /**
     * Use this inside subclasses as a convenience method.
     *
     * @param criterion
     * @return
     */
    @SuppressWarnings( "unchecked" )
    protected List<T> findByCriteria( String orderBy, boolean isAsc, Criterion... criterions )
    {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass( getEntityClass(  ) );

        for ( Criterion criterion : criterions )
        {
            detachedCriteria.add( criterion );
        }

        if ( isAsc )
        {
            detachedCriteria.addOrder( Order.asc( orderBy ) );
        } else
        {
            detachedCriteria.addOrder( Order.desc( orderBy ) );
        }

        if ( BaseDomainEntity.class.isAssignableFrom( entityClass ) )
        {
            detachedCriteria.add( Restrictions.ne( "dataFlag",
                                                   BaseDomainEntity.DELETED.byteValue(  ) ) );
        }

        return getHibernateTemplate(  ).findByCriteria( detachedCriteria );
    }

    /**
     * A convenience method to create a Criteria instance managed by the current
     * transactional Session.
     *
     * @param criterions
     */
    protected DetachedCriteria createCriteria( Criterion... criterions )
    {
        DetachedCriteria criteria = DetachedCriteria.forClass( getEntityClass(  ) );

        for ( Criterion criterion : criterions )
        {
            criteria.add( criterion );
        }

        return criteria;
    }

    /**
     * A convenience method to create a Criteria instance managed by the current
     * transactional Session, and with an ordering.
     *
     * @see #createCriteria(Class,Criterion[])
     */
    protected DetachedCriteria createCriteria( String orderBy, boolean isAsc, Criterion... criterions )
    {
        Assert.hasText( orderBy );

        DetachedCriteria criteria = createCriteria( criterions );

        if ( isAsc )
        {
            criteria.addOrder( Order.asc( orderBy ) );
        } else
        {
            criteria.addOrder( Order.desc( orderBy ) );
        }

        return criteria;
    }

    /**
     * @return the entityClass
     */
    public Class<T> getEntityClass(  )
    {
        return entityClass;
    }

    // -----------------------------------------------------------------
    /**
     * Find the designated page data by given criteria.
     * @param detachedCriteria detachedCriteria
     * @param start   the start record no. of the page
     * @param limit          the pagesize
     * @return the designated page data
     */
    public PageDTO findPageByCriteria( final DetachedCriteria detachedCriteria, final int start, final int limit )
    {	
        if ( BaseDomainEntity.class.isAssignableFrom( entityClass ) )
        {
            detachedCriteria.add( Restrictions.ne( "dataFlag",
                                                   BaseDomainEntity.DELETED.byteValue(  ) ) );
        }

        return (PageDTO) getHibernateTemplate(  ).execute( new HibernateCallback<PageDTO>(  )
            {
                public PageDTO doInHibernate( Session session )
                {
                    Criteria criteria = detachedCriteria.getExecutableCriteria( session );
                    
                    // Get the orginal orderEntries
                    OrderEntry[] orderEntries = getOrders( criteria );
                    // Remove the orders
                    criteria = removeOrders( criteria );
                   
                    // get the original projection
                    Projection projection = getProjection( criteria );
                    
                    int totalCount =
                                                           ( (Number) criteria.setProjection( Projections.rowCount(  ) )
                                                                              .uniqueResult(  ) ).intValue(  );

                    criteria.setProjection( projection );

                    if ( projection == null )
                    {
                        // Set the ResultTransformer to get the same object
                        // structure with hql
                        criteria.setResultTransformer( CriteriaSpecification.ROOT_ENTITY );
                    }

                    // Add the orginal orderEntries
                    criteria = addOrders( criteria, orderEntries );

                    criteria.setFirstResult( start );
                    criteria.setMaxResults( limit );
                    //criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);//数据结果不重复
                    List items = criteria.list(  );

                    criteria.setFirstResult( 0 ).setMaxResults( totalCount );

                    PageDTO pageDTO = new PageDTO(  );

                    pageDTO.setTotalSize( totalCount );
                    pageDTO.setData( items );

                    return pageDTO;
                }
            } );
    }
    //findKnowledgeDAO
    public PageDTO findPageByCriteria( final DetachedCriteria detachedCriteria, final int start, final int limit, final int findKnowledgeIds )
    {	
        if ( BaseDomainEntity.class.isAssignableFrom( entityClass ) )
        {
            detachedCriteria.add( Restrictions.ne( "dataFlag",
                                                   BaseDomainEntity.DELETED.byteValue(  ) ) );
        }

        return (PageDTO) getHibernateTemplate(  ).execute( new HibernateCallback<PageDTO>(  )
            {
                public PageDTO doInHibernate( Session session )
                {
                    Criteria criteria = detachedCriteria.getExecutableCriteria( session );
                    
                    // Get the orginal orderEntries
                    OrderEntry[] orderEntries = getOrders( criteria );
                    // Remove the orders
                    criteria = removeOrders( criteria );
                   
                    // get the original projection
                    Projection projection = getProjection( criteria );
                    
                    int totalCount =
                                                           ( (Number) criteria.setProjection( Projections.rowCount(  ) )
                                                                              .uniqueResult(  ) ).intValue(  );

                    criteria.setProjection( projection );

                    if ( projection == null )
                    {
                        // Set the ResultTransformer to get the same object
                        // structure with hql
                        criteria.setResultTransformer( CriteriaSpecification.ROOT_ENTITY );
                    }

                    // Add the orginal orderEntries
                    criteria = addOrders( criteria, orderEntries );

                    criteria.setFirstResult( start );
                    criteria.setMaxResults( limit );
                    criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);//数据结果不重复
                    List items = criteria.list(  );
                    totalCount=items.size();
                    
                    criteria.setFirstResult( 0 ).setMaxResults( totalCount );

                    PageDTO pageDTO = new PageDTO(  );

                    pageDTO.setTotalSize( totalCount );
                    pageDTO.setData( items );

                    return pageDTO;
                }
            } );
    }
    

    public PageDTO findPageByCriteria( final DetachedCriteria detachedCriteria, final int start, final int limit,final String propertyName )
    {	
        if ( BaseDomainEntity.class.isAssignableFrom( entityClass ) )
        {
            detachedCriteria.add( Restrictions.ne( "dataFlag",
                                                   BaseDomainEntity.DELETED.byteValue(  ) ) );
        }

        return (PageDTO) getHibernateTemplate(  ).execute( new HibernateCallback<PageDTO>(  )
            {
                public PageDTO doInHibernate( Session session )
                {
                    Criteria criteria = detachedCriteria.getExecutableCriteria( session );
                    
                    // Get the orginal orderEntries
                    OrderEntry[] orderEntries = getOrders( criteria );
                    // Remove the orders
                    criteria = removeOrders( criteria );
                    
                    // get the original projection
                    Projection projection = getProjection( criteria );
                    
                    int totalCount =((Number)criteria.setProjection( Projections.rowCount()).uniqueResult()).intValue();
                    criteria.setProjection( projection );
                    if ( projection == null )
                    {
                        // Set the ResultTransformer to get the same object
                        // structure with hql
                        criteria.setResultTransformer( CriteriaSpecification.ROOT_ENTITY );
                    }

                    // Add the orginal orderEntries
                    criteria = addOrders( criteria, orderEntries );
                    criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);//数据结果不重复
                    
                    List items1 = criteria.list(  );
                    totalCount=items1.size();
                    Integer end = (start/limit+1)*limit;
                    List pageList =new ArrayList();
                    for(int i=start;i<items1.size()&&i<end;i++){
                        T pageDate=(T)items1.get(i);
                        pageList.add(pageDate);
                     } 
                    
                    PageDTO pageDTO = new PageDTO();
                    pageDTO.setTotalSize( totalCount );
                    pageDTO.setData( pageList );

                    return pageDTO;
                }
            } );
    }
    
    /**
     * Retrieves projection from the criteria.
     * Since no method declared in the interface, so fetch it from the implementation
     * @see CriteriaImpl#getProjection()
     * @param criteria the criteria
     * @return the Projection
     */
    private static Projection getProjection( Criteria criteria )
    {
        assertType( criteria );

        CriteriaImpl impl = (CriteriaImpl) criteria;

        return impl.getProjection(  );
    }

    private static void assertType( Criteria criteria )
    {
        Assert.notNull( criteria, " criteria is required. " );

        String message = criteria + "";

        if ( ! CriteriaImpl.class.isInstance( criteria ) && LOGGER.isDebugEnabled())
        {
        	LOGGER.debug(message);
        }
    }

    /**
     * Retrieves array of OrderEntry from the criteria.
     * @param criteria the criteria
     * @return the OrderEntry[]
     */
    private static OrderEntry[] getOrders( Criteria criteria )
    {
        assertType( criteria );

        CriteriaImpl impl = (CriteriaImpl) criteria;
        Field field = getOrderEntriesField( criteria );

        try
        {
            return (OrderEntry[]) ( (List) field.get( impl ) ).toArray( new OrderEntry[0] );
        } catch ( Exception e )
        {
            logAndThrowException( criteria, e );
            throw new InternalError( " Runtime Exception impossibility can't throw " );
        }
    }

    /**
     * Remove OrderEntrys from the criteria
     *
     * @param criteria the criteria
     * @return the criteria after removed OrderEntry[]
     */
    private static Criteria removeOrders( Criteria criteria )
    {
        assertType( criteria );

        CriteriaImpl impl = (CriteriaImpl) criteria;

        try
        {
            Field field = getOrderEntriesField( criteria );

            field.set( impl,
                       new ArrayList(  ) );

            return impl;
        } catch ( Exception e )
        {
            logAndThrowException( criteria, e );
            throw new InternalError( " Runtime Exception impossibility can't throw " );
        }
    }

    /**
     * Add OrderEntrys to the criteria
     *
     * @param criteria
     *            the criteria
     * @param orderEntries
     *            the OrderEntry[]
     * @return the criteria after add OrderEntry[]
     */
    private static Criteria addOrders( Criteria criteria, OrderEntry[] orderEntries )
    {
        assertType( criteria );

        CriteriaImpl impl = (CriteriaImpl) criteria;

        try
        {
            Field field = getOrderEntriesField( criteria );

            for ( int i = 0; i < orderEntries.length; i++ )
            {
                List innerOrderEntries = (List) field.get( criteria );

                innerOrderEntries.add( orderEntries[i] );
            }

            return impl;
        } catch ( Exception e )
        {
            logAndThrowException( criteria, e );
            throw new InternalError( " Runtime Exception impossibility can't throw " );
        }
    }

    private static void logAndThrowException( Criteria criteria, Exception e )
    {
        String message = criteria + "";

        if ( LOGGER.isDebugEnabled(  ) )
        {
            LOGGER.debug( message, e );
        }
    }

    private static Field getOrderEntriesField( Criteria criteria )
    {
        Assert.notNull( criteria, " criteria is requried. " );

        try
        {
            Field field = CriteriaImpl.class.getDeclaredField( "orderEntries" );

            field.setAccessible( true );

            return field;
        } catch ( Exception e )
        {
            logAndThrowException( criteria, e );
            throw new InternalError(  );
        }
    }
    /**
     * 用于统计
     * @param detachedCriteria
     * @return
     */
    public Integer statCriteria( final DetachedCriteria detachedCriteria)
    {	
        if ( BaseDomainEntity.class.isAssignableFrom( entityClass ) )
        {
            detachedCriteria.add( Restrictions.ne( "dataFlag",
                                                   BaseDomainEntity.DELETED.byteValue(  ) ) );
        }
        return (Integer) getHibernateTemplate(  ).execute( new HibernateCallback<Integer>()
            {
                public Integer doInHibernate( Session session )
                {
                    Criteria criteria = detachedCriteria.getExecutableCriteria( session );
                    
                    // Get the orginal orderEntries
                    OrderEntry[] orderEntries = getOrders( criteria );
                    // Remove the orders
                    criteria = removeOrders( criteria );
                    
                    // get the original projection
                    //Projection projection = getProjection( criteria );
                    int totalCount =((Number)criteria.setProjection( Projections.rowCount()).uniqueResult()).intValue();
                    return totalCount;
                }
            } );
    }
    
    
    
    
    
}
